/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxEffects =
    {

        /**
         * Class: mxEffects
         *
         * Provides animation effects.
         */

        /**
         * Function: animateChanges
         *
         * Asynchronous animated move operation. See also: <mxMorphing>.
         *
         * Example:
         *
         * (code)
         * graph.model.addListener(mxEvent.CHANGE, function(sender, evt)
         * {
         *   var changes = evt.getProperty('edit').changes;
         *
         *   if (changes.length < 10)
         *   {
         *     mxEffects.animateChanges(graph, changes);
         *   }
         * });
         * (end)
         *
         * Parameters:
         *
         * graph - <mxGraph> that received the changes.
         * changes - Array of changes to be animated.
         * done - Optional function argument that is invoked after the
         * last step of the animation.
         */
        animateChanges: function(graph, changes, done)
        {
            var maxStep = 10;
            var step = 0;

            var animate = function()
            {
                var isRequired = false;

                for (var i = 0; i < changes.length; i++)
                {
                    var change = changes[i];

                    if (change instanceof mxGeometryChange ||
                        change instanceof mxTerminalChange ||
                        change instanceof mxValueChange ||
                        change instanceof mxChildChange ||
                        change instanceof mxStyleChange)
                    {
                        var state = graph.getView().getState(change.cell || change.child, false);

                        if (state != null)
                        {
                            isRequired = true;

                            if (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell))
                            {
                                mxUtils.setOpacity(state.shape.node, 100 * step / maxStep);
                            }
                            else
                            {
                                var scale = graph.getView().scale;

                                var dx = (change.geometry.x - change.previous.x) * scale;
                                var dy = (change.geometry.y - change.previous.y) * scale;

                                var sx = (change.geometry.width - change.previous.width) * scale;
                                var sy = (change.geometry.height - change.previous.height) * scale;

                                if (step == 0)
                                {
                                    state.x -= dx;
                                    state.y -= dy;
                                    state.width -= sx;
                                    state.height -= sy;
                                }
                                else
                                {
                                    state.x += dx / maxStep;
                                    state.y += dy / maxStep;
                                    state.width += sx / maxStep;
                                    state.height += sy / maxStep;
                                }

                                graph.cellRenderer.redraw(state);

                                // Fades all connected edges and children
                                mxEffects.cascadeOpacity(graph, change.cell, 100 * step / maxStep);
                            }
                        }
                    }
                }

                if (step < maxStep && isRequired)
                {
                    step++;
                    window.setTimeout(animate, delay);
                }
                else if (done != null)
                {
                    done();
                }
            };

            var delay = 30;
            animate();
        },

        /**
         * Function: cascadeOpacity
         *
         * Sets the opacity on the given cell and its descendants.
         *
         * Parameters:
         *
         * graph - <mxGraph> that contains the cells.
         * cell - <mxCell> to set the opacity for.
         * opacity - New value for the opacity in %.
         */
        cascadeOpacity: function(graph, cell, opacity)
        {
            // Fades all children
            var childCount = graph.model.getChildCount(cell);

            for (var i=0; i<childCount; i++)
            {
                var child = graph.model.getChildAt(cell, i);
                var childState = graph.getView().getState(child);

                if (childState != null)
                {
                    mxUtils.setOpacity(childState.shape.node, opacity);
                    mxEffects.cascadeOpacity(graph, child, opacity);
                }
            }

            // Fades all connected edges
            var edges = graph.model.getEdges(cell);

            if (edges != null)
            {
                for (var i=0; i<edges.length; i++)
                {
                    var edgeState = graph.getView().getState(edges[i]);

                    if (edgeState != null)
                    {
                        mxUtils.setOpacity(edgeState.shape.node, opacity);
                    }
                }
            }
        },

        /**
         * Function: fadeOut
         *
         * Asynchronous fade-out operation.
         */
        fadeOut: function(node, from, remove, step, delay, isEnabled)
        {
            step = step || 40;
            delay = delay || 30;

            var opacity = from || 100;

            mxUtils.setOpacity(node, opacity);

            if (isEnabled || isEnabled == null)
            {
                var f = function()
                {
                    opacity = Math.max(opacity-step, 0);
                    mxUtils.setOpacity(node, opacity);

                    if (opacity > 0)
                    {
                        window.setTimeout(f, delay);
                    }
                    else
                    {
                        node.style.visibility = 'hidden';

                        if (remove && node.parentNode)
                        {
                            node.parentNode.removeChild(node);
                        }
                    }
                };
                window.setTimeout(f, delay);
            }
            else
            {
                node.style.visibility = 'hidden';

                if (remove && node.parentNode)
                {
                    node.parentNode.removeChild(node);
                }
            }
        }

    };
